package com.example.springboot.aspect;
// 导入必要的包
import com.example.springboot.common.AjaxResult;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.util.Arrays;

/**
 * 用户操作切面类'
 * 用于拦截用户相关操作并进行统一处理
 * 实现日志记录、性能监控和异常处理等横切关注点
 */
@Aspect// 声明该类为一个切面类
@Component// 让Spring自动扫描并注册为Bean
public class UserOperationAspect {
    // 创建日志记录器，用于记录用户操作信息
    private static final Logger logger = LoggerFactory.getLogger(UserOperationAspect.class);

    /**
     * 定义切入点表达式
     * 拦截StudentController类中的所有方法
     */


    @Pointcut("execution(* com.example.springboot.controller.StudentController.*(..))")
    public void userControllerPointcut() {}

//        /**
//     * 定义切点：所有AuthController中的方法
//     */
//    @Pointcut("execution(* com.wz.controller.AuthController.*(..))")
//    public void authControllerPointcut() {}

    /**
     * 定义切点：所有UserService中的方法
     */
    @Pointcut("execution(* com.example.springboot.controller.StudentController.*(..))")
    public void userServicePointcut() {}

    /**
     * 前置通知
     * 在目标方法执行前触发
     * @param joinPoint 连接点对象，包含方法签名和参数信息
     */
    @Before("userControllerPointcut()")// 指定切入点
    public void beforeUserOperation(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName(); // 获取方法名
        String args = Arrays.toString(joinPoint.getArgs());// 获取方法参数
        logger.info("前置通知：准备执行用户操作 - 方法: {}, 参数: {}", methodName, args);
    }

    /**
     * 后置返回通知
     * 在目标方法正常返回后触发
     * @param joinPoint 连接点对象
     * @param result    方法返回结果
     */
    @AfterReturning(pointcut = "userControllerPointcut()", returning = "result")
    public void afterUserOperation(JoinPoint joinPoint, Object result) {
        String methodName = joinPoint.getSignature().getName();
        // 针对AjaxResult类型的返回值进行特殊处理
        if (result instanceof AjaxResult) {
            AjaxResult ajaxResult = (AjaxResult) result;
            logger.info("后置通知：用户操作完成 - 方法: {}, 执行结果: {}", methodName, ajaxResult.get(AjaxResult.MSG_TAG));
        }
    }

    /**
     * 异常通知
     * 在目标方法抛出异常时触发
     * @param joinPoint 连接点对象
     * @param e         捕获的异常
     */
    @AfterThrowing(pointcut = "userControllerPointcut()", throwing = "e")
    public void afterThrowing(JoinPoint joinPoint, Exception e) {
        String methodName = joinPoint.getSignature().getName();
        logger.error("异常通知：用户操作异常 - 方法: {}, 异常信息: {}", methodName, e.getMessage());// 记录完整异常堆栈
    }

    /**
     * 环绕通知
     * 环绕目标方法执行，可控制方法的执行时机和结果
     * @param joinPoint 可执行的连接点对象
     * @return 方法执行结果
     * @throws Throwable 方法抛出的异常
     */
    @Around("userServicePointcut()")
    public Object aroundUserOperation(ProceedingJoinPoint joinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();// 记录开始时间
        String methodName = joinPoint.getSignature().getName();
        
        try {
            // 执行目标方法
            Object result = joinPoint.proceed();
            
            long endTime = System.currentTimeMillis();
            logger.info("环绕通知：方法 {} 执行完成，耗时: {}ms", methodName, (endTime - startTime));
            
            return result;// 返回方法执行结果
        } catch (Throwable e) {
            long endTime = System.currentTimeMillis();
            logger.error("环绕通知：方法 {} 执行异常，耗时: {}ms, 异常: {}",
                methodName, (endTime - startTime), e.getMessage());
            throw e;// 重新抛出异常
        }
    }
} 